// Copyright (C) 2010  Andrew H. Chan
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// 
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// Header file that contains common typedefs.
// Set NUM_LOCI (below) to the number of loci and NUM_ALLELES (below) to the  number of alleles that the program should be compiled to handle

#ifndef _TYPEDEFS_H__
#define _TYPEDEFS_H__

#include "basic_includes.h"

// Macros for square-multiply power function
// Works for exp < 32 
#define INTPOW5(base, exp) ((((exp)&1)>0) ? (base) : 1)
#define INTPOW4(base, exp) (((((exp)&1)>0) ? (base) : 1) * INTPOW5(((base)*(base)), ((exp) >> 1)))
#define INTPOW3(base, exp) (((((exp)&1)>0) ? (base) : 1) * INTPOW4(((base)*(base)), ((exp) >> 1)))
#define INTPOW2(base, exp) (((((exp)&1)>0) ? (base) : 1) * INTPOW3(((base)*(base)), ((exp) >> 1)))
#define INTPOW1(base, exp) (((((exp)&1)>0) ? (base) : 1) * INTPOW2(((base)*(base)), ((exp) >> 1)))
#define INTPOW(base, exp) (((((exp)&1)>0) ? (base) : 1) * INTPOW1(((base)*(base)), ((exp) >> 1)))

// Set NUM_LOCI to the number of loci and NUM_ALLELES to the  number of alleles that the program should be compiled to handle
const unsigned int NUM_LOCI = 3;
const unsigned int NUM_ALLELES = 2;

// Number of different possible haplotype configurations
const unsigned int NUM_HAPS = INTPOW(NUM_ALLELES + 1, NUM_LOCI)-1;

// namespaces
namespace ublas = boost::numeric::ublas;

// forward declarations
// Multidimensional matrix, defined in multiM.h and multiM.cpp
// Contains a few functions specifically related to sample configurations
class MultiM;
class Packed_Config;

// typedefs
typedef unsigned char uchar;
typedef unsigned int uint;
typedef unsigned long long uint64;

typedef std::vector<int> vi;
typedef std::vector<int>::iterator vi_iter;
typedef std::vector<std::vector<int> > vi2;
typedef std::vector<std::vector<int> >::iterator vi2_iter;
typedef std::vector<std::vector<std::vector<int> > > vi3;
typedef std::vector<std::vector<std::vector<int> > >::iterator vi3_iter;
typedef std::vector<double> vd;
typedef std::vector<double>::iterator vd_iter;
typedef std::vector<std::vector<double> > vd2;
typedef std::vector<std::vector<double> >::iterator vd2_iter;

typedef std::vector<bool> bit_vector;

// matrix types for linear system solving
// Notice that the matrix is in column major order!
// This is for compatibility with LAPACK.
// NOTE: LAPACK is not used yet in the Mac version of this program
//typedef ublas::matrix<double, ublas::column_major> matrix_t;
typedef ublas::vector<double> vector_t;
// Sparse representations
typedef ublas::compressed_matrix<double, ublas::column_major> matrix_t;
//typedef ublas::mapped_matrix<double, ublas::column_major> matrix_t;
//typedef ublas::compressed_vector<double> vector_t;
//typedef ublas::mapped_vector<double> vector_t;

// individuals_t is used by the parser to store the input samp config
typedef std::vector<std::pair< vi, int > > individuals_t; 
typedef std::vector<std::pair< vi, int > >::iterator individuals_t_iter;

// Index types
// signed int used so that -1 means "unspecified allele"
typedef std::vector<int> index_t;

// sample configuration type
typedef MultiM samp_config_t;

// Packed configuration type for sample configurations
// Use std::map or boost::unordered_map
typedef Packed_Config packed_config_t;

// Hash map that maps from configuration to double
typedef boost::unordered_map<samp_config_t, double> samp_hash_t;
typedef boost::unordered_map<packed_config_t, double> packed_hash_t;
// Hash map to store probabilities for each configuration
typedef packed_hash_t probs_type;

// Hash map that maps configuration to signed int
typedef boost::unordered_map<packed_config_t, int> packed_int_hash_t;
// Hash map that maps configuration to unsigned int
typedef boost::unordered_map<packed_config_t, uint> packed_uint_hash_t;

// Hash map that maps configuration to signed int
typedef boost::unordered_map<samp_config_t, int> samp_int_hash_t;
// Hash map that maps configuration to unsigned int
typedef boost::unordered_map<samp_config_t, uint> samp_uint_hash_t;

// These map the haplotype to the index and vice versa
typedef unsigned char hap_id_t;
typedef unsigned char quantity_t;
//typedef size_t hap_id_t;
//typedef size_t quantity_t;

typedef boost::unordered_map<index_t, hap_id_t> hap_to_id_t;
typedef boost::unordered_map<hap_id_t, index_t> id_to_hap_t;

// index_mask_pair_t pairs together an index and a vector<int> of loci that the index defines
typedef std::pair<index_t, vi> index_mask_pair_t;
typedef std::pair<hap_id_t, vi> hap_id_mask_pair_t;

// degree_pair_t pairs together the degree of an index and the corresponding index-mask pair
typedef std::pair<size_t, hap_id_mask_pair_t> degree_pair_t;

typedef std::vector<degree_pair_t> degree_list_t;

// Adjacency list typedefs
// outgoing adjacency list 
typedef std::pair<packed_config_t, double> out_edge_t; 
typedef std::vector<out_edge_t> vec_out_edge_t;

// samp_config_t -> list of samp_config_t and coefficients
typedef boost::unordered_map<packed_config_t, vec_out_edge_t > adj_list_t;

typedef std::vector<packed_config_t> seq_config_t;

// Containers of packed configurations
typedef std::vector<packed_config_t> packed_vector_t; 
typedef std::queue<packed_config_t> packed_queue_t;
typedef std::stack<packed_config_t> packed_stack_t;

// Containers of sample configurations
typedef std::vector<samp_config_t> samp_vector_t; 
typedef std::queue<samp_config_t> samp_queue_t;
typedef std::stack<samp_config_t> samp_stack_t;

/////////
// typedefs for strongly connected components (Tarjan's algorithm)
typedef std::vector< packed_vector_t > vv_packed_config_t;
typedef std::vector< samp_vector_t > vv_samp_config_t;
// post-number
// pair <post-number, scc_id>
typedef std::pair< uint, size_t > scc_post_scc_t;
typedef std::vector<scc_post_scc_t> scc_rank_t;
/////////

#endif
